import { useEffect, useState, useRef, MutableRefObject } from 'react';
import { viewUtils } from '@/utils/arcgis/index';
import { jsapi } from '@/utils/arcgis';
import throttle from 'lodash/throttle';

type BasicTarget<T = HTMLElement> = (() => T | null) | T | null | MutableRefObject<T | undefined>;

type TargetElement = HTMLElement | Document | Window;

interface IOrientation {
  x: number;
  y: number;
  z: number;
}

export function getTargetElement(
  target?: BasicTarget<TargetElement>,
  defaultElement?: TargetElement,
): TargetElement | undefined | null {
  if (!target) {
    return defaultElement;
  }

  let targetElement: TargetElement | undefined | null;

  if (typeof target === 'function') {
    targetElement = target();
  } else if ('current' in target) {
    targetElement = target.current;
  } else {
    targetElement = target;
  }

  return targetElement;
}

/**
 * compass hook - compass逻辑抽成hook
 *
 * @param target - 指定罗盘的react ref 或者 div元素
 * @returns [isLoading, reset] - 罗盘加载状态，和重置地图方向函数
 
 * @author leway
 * @date 2020-07-16
 * @beta
 */
function useCompass(target: BasicTarget): [boolean, () => void] {
  const [isLoading, setIsLoading] = useState<boolean>(true);
  const vmRef = useRef<any>();
  const [orientation, setOrientation] = useState<Partial<IOrientation>>({ z: 0 });
  const setOrientationRef = useRef(
    throttle((data: IOrientation) => {
      setOrientation(data);
    }, 160),
  );

  const watchHandle = useRef<any>();

  useEffect(() => {
    if (!target) return;
    init();
    return () => {
      watchHandle.current && watchHandle.current!.remove();
    };
  }, [target]);

  useEffect(() => {
    const targetElement = getTargetElement(target);
    if (targetElement) {
      (<HTMLElement>targetElement).style.transform = `rotateZ(${orientation.z}deg)`;
    }
  }, [orientation, target]);

  async function init() {
    const view = await viewUtils.isViewReady();
    const [CompassViewModel] = await jsapi.load(['esri/widgets/Compass/CompassViewModel']);
    vmRef.current = new CompassViewModel({ view });
    const targetElement = getTargetElement(target);

    setTimeout(() => {
      // @ts-ignore
      if (targetElement && targetElement.style) {
        (<HTMLElement>targetElement).style.willChange = 'auto';
      }
    }, 0);
    // targetElement.style.transition = 'transform linear .1s';

    watchHandle.current = vmRef.current.watch('orientation', orientation => {
      setOrientationRef.current && setOrientationRef.current(orientation);
    });
    setIsLoading(false);
  }

  function setAngle() {}

  function reset() {
    if (!vmRef.current) {
      return;
    }
    vmRef.current.reset();
  }

  return [isLoading, reset];
}

export default useCompass;
